<template>
  <NFlex :vertical="!group.vertical" style="flex: 1">
    <NFlex
      :justify="group.vertical ? 'center' : group.align"
      :align="group.vertical ? group.align : 'center'"
      style="margin-bottom: 20px"
    >
      <NSteps
        class="nv-steps"
        :vertical="group.vertical"
        :size="group.size"
        :status
        :current
        :on-update:current="
          mode === 'view' ? (val: number) => (current = val) : undefined
        "
      >
        <NStep
          v-for="(item, index) in group.items"
          :key="index"
          :disabled="item.disabled"
          :description="item.description"
        >
          <template #title>
            <component
              :is="item.title"
              v-if="typeof item.title === 'function'"
            />
            <template v-else>
              {{ item.title }}
            </template>
          </template>

          <template v-if="item.icon" #icon>
            <component :is="item.icon" />
          </template>
          <template v-else-if="group.icon" #icon>
            <component :is="group.icon" />
          </template>
        </NStep>

        <template v-if="group.finishIcon" #finish-icon>
          <component :is="group.finishIcon" />
        </template>
        <template v-if="group.errorIcon" #error-icon>
          <component :is="group.errorIcon" />
        </template>
      </NSteps>
    </NFlex>

    <Transition :name="animationName" mode="out-in">
      <div v-if="flush" class="nv-steps-content">
        <NaiveFormFields
          :key="current"
          v-model:form="formData"
          :fields="formGroupFields[current - 1]"
          :option="props.option"
          :mode="props.mode"
        >
          <template v-for="(_, name) in slots" #[name]="slotData">
            <slot :name="name" v-bind="slotData || {}" />
          </template>
        </NaiveFormFields>
      </div>
    </Transition>
  </NFlex>
</template>

<script setup lang="ts">
import type { StepsProps } from 'naive-ui'
import type { NvFormMode, NvFormOption } from '@/form/types'
import type { RowData } from '@/types'
import { NFlex, NStep, NSteps } from 'naive-ui'
import { computed, ref, watch } from 'vue'
import NaiveFormFields from '../FormFields.vue'
import { useGroup } from './use-group'

interface Props {
  option: NvFormOption
  mode?: NvFormMode
}
const props = defineProps<Props>()
const slots = defineSlots()

const formData = defineModel<RowData>('form', { required: true })
const current = defineModel<number>('current', { required: true })
const status = defineModel<StepsProps['status']>('status', { required: true })

const group = computed(() => props.option.group!)

const flush = ref(true)
type AnimationName = 'nv-left' | 'nv-right' | 'nv-top' | 'nv-bottom'
const animationName = ref<AnimationName>(group.value.vertical ? 'nv-top' : 'nv-left')
watch(current, (newVal, oldVal) => {
  const { vertical } = group.value
  if (newVal > oldVal) {
    animationName.value = vertical ? 'nv-bottom' : 'nv-right'
  }
  else {
    animationName.value = vertical ? 'nv-top' : 'nv-left'
  }
  flush.value = false
  // nextTick 无法触发离开动画
  // nextTick(() => {
  //   flush.value = true
  // })
  setTimeout(() => {
    flush.value = true
  }, 50)
})

const formGroupFields = useGroup(props)
</script>

<style lang="scss">
.nv-steps {
  width: fit-content;
  height: fit-content;

  &.n-steps--vertical:not(.n-steps--show-description) > .n-step {
    padding-bottom: 20px;
  }
  &:not(.n-steps--vertical) .n-step-splitor {
    min-width: 20px;
  }
}
.nv-steps-content {
  flex: 1 0 0;
  transition: all var(--nv-steps-transition-duration, 0.1s) ease;
}

@each $direction in left, right, top, bottom {
  // 判断是 translateX 还是 translateY
  $axis: if($direction == 'left' or $direction == 'right', 'translateX', 'translateY');

  // 判断方向是正还是负
  $offset: if(
    $direction == 'left' or $direction == 'top',
    'calc(-1 * var(--nv-steps-translate, 20px))',
    'var(--nv-steps-translate, 20px)'
  );

  .nv-#{$direction}-enter-from,
  .nv-#{$direction}-leave-to {
    opacity: 0;
    transform: #{$axis }(#{$offset});
  }
}
</style>
